]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
Approve room invitations
authorGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>
Thu, 30 Jun 2011 12:05:41 +0000 (14:05 +0200)
committerGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>
Thu, 7 Jul 2011 09:18:46 +0000 (11:18 +0200)
We use to rely on Empathy for this but as we plan to allow users to be
connected on IM without having Empathy running the Shell should do it now.

https://bugzilla.gnome.org/show_bug.cgi?id=653740

js/ui/notificationDaemon.js
js/ui/telepathyClient.js
src/shell-tp-client.c
src/shell-tp-client.h

index 35eb58166653977042b87fb6aa0b34e79b4482fd..66bd0c58fd2479c7fd483ddca55c914426a32605 100644 (file)
@@ -190,9 +190,10 @@ NotificationDaemon.prototype = {
                      actions, hints, timeout) {
         let id;
 
-        // Filter out chat and presence notifications from Empathy, since we
+        // Filter out chat, presence and invitation notifications from Empathy, since we
         // handle that information from telepathyClient.js
         if (appName == 'Empathy' && (hints['category'] == 'im.received' ||
+              hints['category'] == 'x-empathy.im.room-invitation' ||
               hints['category'] == 'presence.online' ||
               hints['category'] == 'presence.offline')) {
             // Ignore replacesId since we already sent back a
index d81b40a76ae99dd2ea5b0536f40ed38f6e40598d..8a476011ae87170e5c86a41291518f0652ad3a15 100644 (file)
@@ -178,21 +178,65 @@ Client.prototype = {
         }
     },
 
-    _approveChannels: function(approver, account, conn, channels,
-                               dispatchOp, context) {
-        // Approve the channels right away as we are going to handle it
-        dispatchOp.claim_with_async(this._tpClient,
-                                    Lang.bind (this, function(dispatchOp, result) {
-            try {
-                dispatchOp.claim_with_finish(result);
-                this._handlingChannels(account, conn, channels);
-            } catch (err) {
-                global.logError('Failed to Claim channel: ' + err);
-            }}));
+    _displayRoomInvitation: function(conn, channel, dispatchOp, context) {
+        // We can only approve the rooms if we have been invited to it
+        let selfHandle = channel.group_get_self_handle();
+        if (selfHandle == 0) {
+            Shell.decline_dispatch_op(context, 'Not invited to the room');
+            return;
+        }
+
+        let [invited, inviter, reason, msg] = channel.group_get_local_pending_info(selfHandle);
+        if (!invited) {
+            Shell.decline_dispatch_op(context, 'Not invited to the room');
+            return;
+        }
+
+        // Request a TpContact for the inviter
+        Shell.get_tp_contacts(conn, [inviter],
+                contactFeatures,
+                Lang.bind(this, this._createRoomInviteSource, channel, context, dispatchOp));
+
+        context.delay();
+     },
+
+    _createRoomInviteSource: function(connection, contacts, failed, channel, context, dispatchOp) {
+        if (contacts.length < 1) {
+            Shell.decline_dispatch_op(context, 'Failed to get inviter');
+            return;
+        }
 
+        // We got the TpContact
+        let source = new RoomInviteSource(dispatchOp);
+        Main.messageTray.add(source);
+
+        let notif = new RoomInviteNotification(source, dispatchOp, channel, contacts[0]);
+        source.notify(notif);
         context.accept();
     },
 
+    _approveChannels: function(approver, account, conn, channels,
+                               dispatchOp, context) {
+        let channel = channels[0];
+        let [targetHandle, targetHandleType] = channel.get_handle();
+
+        if (targetHandleType == Tp.HandleType.CONTACT) {
+            // Approve private text channels right away as we are going to handle it
+            dispatchOp.claim_with_async(this._tpClient,
+                                        Lang.bind(this, function(dispatchOp, result) {
+                try {
+                    dispatchOp.claim_with_finish(result);
+                    this._handlingChannels(account, conn, channels);
+                } catch (err) {
+                    throw new Error('Failed to Claim channel: ' + err);
+                }}));
+
+            context.accept();
+        } else {
+            this._displayRoomInvitation(conn, channel, dispatchOp, context);
+        }
+    },
+
     _handleChannels: function(handler, account, conn, channels,
                               requests, user_action_time, context) {
         this._handlingChannels(account, conn, channels);
@@ -684,3 +728,86 @@ ChatNotification.prototype = {
         this.source.respond(text);
     }
 };
+
+function RoomInviteSource(dispatchOp) {
+    this._init(dispatchOp);
+}
+
+RoomInviteSource.prototype = {
+    __proto__: MessageTray.Source.prototype,
+
+    _init: function(dispatchOp) {
+        MessageTray.Source.prototype._init.call(this, _("Invitation"));
+
+        this._setSummaryIcon(this.createNotificationIcon());
+
+        this._dispatchOp = dispatchOp;
+
+        // Destroy the source if the channel dispatch operation is invalidated
+        // as we can't approve any more.
+        this._invalidId = dispatchOp.connect('invalidated',
+                                             Lang.bind(this, function(domain, code, msg) {
+            this.destroy();
+        }));
+    },
+
+    destroy: function() {
+        if (this._invalidId != 0) {
+            this._dispatchOp.disconnect(this._invalidId);
+            this._invalidId = 0;
+        }
+
+        MessageTray.Source.prototype.destroy.call(this);
+    },
+
+    createNotificationIcon: function() {
+        // FIXME: We don't have a 'chat room' icon (bgo #653737) use
+        // system-users for now as Empathy does.
+        return new St.Icon({ icon_name: 'system-users',
+                             icon_type: St.IconType.FULLCOLOR,
+                             icon_size: this.ICON_SIZE });
+    }
+}
+
+function RoomInviteNotification(source, dispatchOp, channel, inviter) {
+    this._init(source, dispatchOp, channel, inviter);
+}
+
+RoomInviteNotification.prototype = {
+    __proto__: MessageTray.Notification.prototype,
+
+    _init: function(source, dispatchOp, channel, inviter) {
+        MessageTray.Notification.prototype._init.call(this,
+                                                      source,
+                                                      /* translators: argument is a room name like
+                                                       * room@jabber.org for example. */
+                                                      _("Invitation to %s").format(channel.get_identifier()),
+                                                      null,
+                                                      { customContent: true });
+        this.setResident(true);
+
+        /* translators: first argument is the name of a contact and the second
+         * one the name of a room. "Alice is inviting you to join room@jabber.org
+         * for example. */
+        this.addBody(_("%s is inviting you to join %s").format(inviter.get_alias(), channel.get_identifier()));
+
+        this.addButton('decline', _("Decline"));
+        this.addButton('accept', _("Accept"));
+
+        this.connect('action-invoked', Lang.bind(this, function(self, action) {
+            switch (action) {
+            case 'decline':
+                dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE,
+                                                '', function(src, result) {
+                    src.leave_channels_finish(result)});
+                break;
+            case 'accept':
+                dispatchOp.handle_with_time_async('', global.get_current_time(),
+                                                  function(src, result) {
+                    src.handle_with_time_finish(result)});
+                break;
+            }
+            this.destroy();
+        }));
+    }
+};
index af507bc886e9efa9271c78921e99a770d436e393..018f233e5dd65258f134b03c85b240c9b6c0aab1 100644 (file)
@@ -101,6 +101,15 @@ shell_tp_client_init (ShellTpClient *self)
   /* Approver */
   tp_base_client_add_approver_filter (TP_BASE_CLIENT (self), filter);
 
+  /* Approve room invitations. We don't handle or observe room channels so
+   * just register this filter for the approver. */
+  tp_base_client_take_approver_filter (TP_BASE_CLIENT (self), tp_asv_new (
+      TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
+        TP_IFACE_CHANNEL_TYPE_TEXT,
+      TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT,
+        TP_HANDLE_TYPE_ROOM,
+      NULL));
+
   /* Handler */
   tp_base_client_add_handler_filter (TP_BASE_CLIENT (self), filter);
 
@@ -371,3 +380,15 @@ shell_get_contact_events (TplLogManager *log_manager,
                                              NULL, NULL,
                                              callback, NULL);
 }
+
+/* gjs doesn't allow us to craft a GError so we need a C wrapper */
+void
+shell_decline_dispatch_op (TpAddDispatchOperationContext *context,
+    const gchar *message)
+{
+  GError *error = g_error_new_literal (TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
+      message);
+
+  tp_add_dispatch_operation_context_fail (context, error);
+  g_error_free (error);
+}
index 064c6abe5b9aba67c2b0815355b355a2dbbb8f2d..b32304587d5d4777cd99d10faccb7dd856de7b54 100644 (file)
@@ -111,5 +111,8 @@ void shell_get_contact_events (TplLogManager *log_manager,
                                guint num_events,
                                GAsyncReadyCallback callback);
 
+void shell_decline_dispatch_op (TpAddDispatchOperationContext *context,
+                                const gchar *message);
+
 G_END_DECLS
 #endif /* __SHELL_TP_CLIENT_H__ */